package com.it.gmall.order.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.it.gmall.common.constant.RedisConst;
import com.it.gmall.common.util.HttpClientUtil;
import com.it.gmall.model.enums.OrderStatus;
import com.it.gmall.model.enums.ProcessStatus;
import com.it.gmall.model.order.OrderDetail;
import com.it.gmall.model.order.OrderInfo;
import com.it.gmall.mq.consts.MqConst;
import com.it.gmall.mq.service.SendMsgService;
import com.it.gmall.order.mapper.OrderApiMapper;
import com.it.gmall.order.mapper.OrderDetailMapper;
import com.it.gmall.product.client.ProductFeignClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OrderApiServiceImpl implements OrderApiService {

    @Value("ware.url")
    private String wareUrl;

    @Autowired
    private ProductFeignClient productFeignClient;

    @Autowired
    private OrderApiMapper orderApiMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private OrderApiServiceAsync orderApiServiceAsync;

    @Autowired
    private SendMsgService sendMsgService;

    // 判断商品是否有库存
    // 下单数量-库存数量>0
    @Override
    public Boolean isHaveStock(OrderDetail orderDetail) {
        return "1".equals(HttpClientUtil.doGet(wareUrl + "/hasStock?skuId="+
                orderDetail.getSkuId() + "&num=" + orderDetail.getSkuNum()));
    }

    // 提交订单数据 三个操作需要保证事务
    @Override
    public long subOrder(OrderInfo orderInfo) {
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        // 1.提交订单 主表和详情表
        // 1.1 主表
        orderInfo.setOrderStatus(OrderStatus.UNPAID.name()); // 订单状态 获取英文名称 UNPAID

        String outTradeNo = "GMALL"+System.currentTimeMillis()+ new Random().nextInt(20);
        orderInfo.setOutTradeNo(outTradeNo); // 订单交易编号 保证唯一 用于第三方支付的时候使用

        StringBuilder tradeBody = new StringBuilder(); // 订单描述 用于手机扫码显示

        if(!CollectionUtils.isEmpty(orderDetailList)){
            for (OrderDetail orderDetail : orderDetailList) { // 为防止页面篡改价格 在提交数据之前查询商品实时价格
                BigDecimal skuPrice = productFeignClient.getSkuPrice(orderDetail.getSkuId());
                orderDetail.setOrderPrice(skuPrice);

                tradeBody.append(orderDetail.getSkuName()+":"); // 订单描述
            }
            orderInfo.sumTotalAmount(); // 计算所有商品的价格总和 数量*单价
        }

        if(tradeBody.length()>100){ // 判断订单描述的长度是否大于100 如果大于 则截取前一百位
            orderInfo.setTradeBody(tradeBody.substring(0,100));
        }else{
            orderInfo.setTradeBody(tradeBody.toString());
        }

        Calendar c = Calendar.getInstance();
        orderInfo.setCreateTime(c.getTime()); // 创建时间
        c.add(Calendar.HOUR,2); // 两小时后过期
        orderInfo.setExpireTime(c.getTime()); // 过期时间

        orderInfo.setProcessStatus(ProcessStatus.UNPAID.name()); // 进度状态

        orderApiMapper.insert(orderInfo); // 将订单主表的信息保存到数据库中

        // 1.2 详情表-订单主键回填
        // 获取每一个订单的id 方便后续删除购物车的时候对redis的操作
        List<String> ids = new ArrayList<>(orderDetailList.size());
        // 获取每一个订单的id 并转换为long类型 给DB使用 数据库类型转换索引存失效 数据库中是int类型
        List<Long> idsLong = new ArrayList<>(orderDetailList.size());
        orderDetailList.stream().forEach(orderDetail -> {
            orderDetail.setOrderId(orderInfo.getId()); // 外键设置
            ids.add(orderDetail.getSkuId().toString()); // redis使用
            idsLong.add(orderDetail.getSkuId());
            orderDetailMapper.insert(orderDetail);
        });

        // 2.删除原有购物车的数据 (双写 redis和DB)
        // 2.1 删除redis中的数据 user:3:cart
        /*String cacheKey = RedisConst.USER_KEY_PREFIX + orderInfo.getUserId() + RedisConst.USER_CART_KEY_SUFFIX;
        redisTemplate.opsForHash().delete(cacheKey,ids.toArray());*/

        // 2.2 批量删除DB中的购物车数据-使用异步的方式
        /*orderApiServiceAsync.deleteCartInfo(orderInfo.getUserId(),idsLong);*/

        // 3.倒计时两小时 为了配合支付宝动态二维码有效过期时间（rabbitmq 延迟队列 基于插件）
        /*sendMsgService.sendMsgDelayedMsg(MqConst.EXCHANGE_DIRECT_ORDER_CANCEL,MqConst.ROUTING_ORDER_CANCEL,orderInfo.getId(),MqConst.DELAY_TIME);
*/
        // 返回订单id给页面
        return orderInfo.getId();
    }

    // 查询订单详情
    @Override
    public OrderInfo getOrderInfo(Long orderId) {
        OrderInfo orderInfo = orderApiMapper.selectById(orderId);
        // 子订单
        List<OrderDetail> detailList = orderDetailMapper.selectList(new QueryWrapper<OrderDetail>().eq("order_id", orderId));
        orderInfo.setOrderDetailList(detailList);
        return orderInfo;
    }

    // 更改订单状态和支付的状态
    @Override
    public void updateOrderInfoStatus(Long orderId, ProcessStatus processStatus) {
        // 获取订单得信息
        OrderInfo orderInfo = getOrderInfo(orderId);
        orderInfo.setOrderStatus(processStatus.getOrderStatus().name()); // 订单状态
        orderInfo.setProcessStatus(processStatus.name()); // 进度状态
        // 更新db
        orderApiMapper.updateById(orderInfo);

    }

    // 初始化库存对象
    @Override
    public List<Map> initWareInfo(List<OrderInfo> orderInfos) {
        return orderInfos.stream().map(orderInfo -> {
            return getMap(orderInfo.getId(),orderInfo);
        }).collect(Collectors.toList());
    }

    // 初始化库存对象
    @Override
    public String initWareInfo(Long orderId) {
        // 根据订单id查询对象
        OrderInfo orderInfo = getOrderInfo(orderId);
        Map map = getMap(orderId, orderInfo);
        return JSON.toJSONString(map);
    }

    private Map getMap(Long orderId, OrderInfo orderInfo) {
        // 封装对象返回
        Map map = new HashMap();
        map.put("orderId",orderId); // 订单编号
        map.put("consignee",orderInfo.getConsignee()); // 收货人
        map.put("consigneeTel",orderInfo.getConsigneeTel()); // 收货人电话
        map.put("orderComment",orderInfo.getOrderComment()); // 订单备注
        map.put("orderBody",orderInfo.getTradeBody()); // 订单概要
        map.put("deliveryAddress",orderInfo.getDeliveryAddress()); // 发货地址
        map.put("paymentWay","ONLINE".equals(orderInfo.getPaymentWay())?"2":"1"); // 支付方式 ‘1’ 为货到付款，‘2’为在线支付。
        if(orderInfo.getWareId()!=null){
            map.put("wareId",orderInfo.getWareId());
        }
        if(null!=orderInfo.getOrderDetailList()){
            // 订单详情
            List<Map> detailList = orderInfo.getOrderDetailList().stream().map(orderDetail -> {
                HashMap detailMap = new HashMap<>();
                detailMap.put("skuId",orderDetail.getSkuId()); // skuId
                detailMap.put("skuNum",orderDetail.getSkuNum()); // 数量
                detailMap.put("skuName",orderDetail.getSkuName()); // 名称
                return detailMap;
            }).collect(Collectors.toList());
            map.put("details",detailList);
        }
        return map;
    }

    // 拆单
    // orderId  4
    // wareSkuMap  [{"wareId":"1","skuIds":["11"]},{"wareId":"2","skuIds":["1","13","14"]}]
    @Override
    public List<OrderInfo> splitOrder(long orderId, String wareSkuMap) {
        // 转换库存对象
        List<Map> wareSkuMapList = (List<Map>) JSONObject.parse(wareSkuMap);
        // 根据id获取原始订单
        OrderInfo orderInfoOrigin = getOrderInfo(orderId);
        // 获取原始订单的子订单
        List<OrderDetail> originOrderDetailList = orderInfoOrigin.getOrderDetailList();
        // 有几个库存对象就需要新建几个订单 即需要拆成几个订单
        List<OrderInfo> orderInfoList = wareSkuMapList.stream().map(map -> {
            String wareId = (String) map.get("wareId"); // 仓库id
            List<String> skuIds = (List<String>) map.get("skuIds"); // 这个仓库包含的产品id
            OrderInfo orderInfoSub = new OrderInfo();
            BeanUtils.copyProperties(orderInfoOrigin,orderInfoSub); // 复制属性
            orderInfoSub.setId(null); // 主键自增长 防止主键冲突
            orderInfoSub.setWareId(wareId); // 仓库id
            orderInfoSub.setParentOrderId(orderInfoOrigin.getId()); // 父id

            // 获取子订单
            List<OrderDetail> orderDetailList = originOrderDetailList.stream().filter(orderDetail -> {
                if(skuIds.contains(orderDetail.getSkuId().toString())){
                    return true;
                }else {
                    return false;
                }
            }).collect(Collectors.toList());

            orderInfoSub.setOrderDetailList(orderDetailList);

            orderInfoSub.sumTotalAmount(); // 计算总金额

            // 将拆分的订单插入到数据库中
            orderApiMapper.insert(orderInfoSub);

            // 获取新插入数据的id
            Long subOrderId = orderInfoSub.getId();
            orderDetailList.stream().forEach(orderDetail -> {
                orderDetail.setOrderId(subOrderId);
                orderDetailMapper.updateById(orderDetail);
            });
            return orderInfoSub;
        }).collect(Collectors.toList());

        // 更改原始订单的状态为已拆单
        updateOrderInfoStatus(orderId,ProcessStatus.SPLIT);
        return orderInfoList;
    }

    // 修改减库存之后的结果
    @Override
    public void updateLockStockStatus(String result) {
        Map map = (Map) JSONObject.parse(result);
        String orderId = (String) map.get("orderId");
        String status = (String) map.get("status");
        if("DEDUCTED".equals(status)){ // 已减库存 待发货
            updateOrderInfoStatus(Long.parseLong(orderId),ProcessStatus.WAITING_DELEVER);
        }else{
            log.error("库存存在异常，转人工处理......");
            updateOrderInfoStatus(Long.parseLong(orderId),ProcessStatus.STOCK_EXCEPTION);
        }
    }
}
